package AdvancedEncryptionStandard;

import constant.CONS;

import java.util.Arrays;

public class ByteStream {
    private final byte[] value;
    private final int byteLength;

    public ByteStream(byte[] value, int byteLength) throws Exception {
        if (byteLength <= 0 || byteLength < value.length) {
            throw new Exception(CONS.INDEX_WRONG.getMsg());
        }
        this.value = value;
        this.byteLength = byteLength;
    }

    public ByteStream(int byteLength) throws Exception {
        if (byteLength <= 0) {
            throw new Exception(CONS.INDEX_WRONG.getMsg());
        }
        this.byteLength = byteLength;
        this.value = new byte[byteLength];
    }

    public ByteStream(byte[] value) {
        this.byteLength = value.length;
        this.value = new byte[byteLength];
        System.arraycopy(value, 0, this.value, 0, value.length);
    }

    /**
     * 设置值的成员函数
     *
     * @param index 要设置的值的下标，下标从1开始，而不是从0开始
     * @param v     要设置的下标的值，一个byte类型
     * @throws Exception 下标出错的Exception
     */
    public void set(int index, byte v) throws Exception {
        if (index <= 0 || index > value.length) {
            throw new Exception(CONS.INDEX_WRONG.getMsg());
        }
        this.value[index - 1] = v;
    }

    /**
     * 通过行和列来设置值的成员函数，更加有矩阵的味道
     *
     * @param rowIndex 行下标
     * @param colIndex 列下标
     * @param v        要设置的值
     * @throws Exception 下标出错的Exception
     */
    public void set(int rowIndex, int colIndex, byte v) throws Exception {
        set(rowIndex + (colIndex - 1) * 4, v);
    }

    /**
     * 设置值的成员函数，批量设置值
     *
     * @param index 要设置的值的下标，下标从1开始，而不是从0开始
     * @param vs    要设置的下标的值，一个byte类型的数组
     * @throws Exception 下标出错的Exception
     */
    public void set(int index, byte[] vs) throws Exception {
        if (index <= 0 || index + vs.length - 1 > value.length) {
            throw new Exception(CONS.INDEX_WRONG.getMsg());
        }
        for (byte v : vs) {
            this.value[index++ - 1] = v;
        }
    }

    /**
     * 获取值的成员函数
     *
     * @param index 要获取的值的下标，下标从1开始，而不是从0开始
     * @return 要获取的值，一个byte类型
     * @throws Exception 下标出错的Exception
     */
    public byte get(int index) throws Exception {
        if (index <= 0 || index > value.length) {
            throw new Exception(CONS.INDEX_WRONG.getMsg());
        }
        return this.value[index - 1];
    }

    // 0   4   8  12
    // 1   5   9  13
    // 2   6  10  14
    // 3   7  11  15
    public byte get(int rowIndex, int colIndex) throws Exception {
        return get(rowIndex + (colIndex - 1) * 4);
    }

    /**
     * @return 返回字节数组
     */
    public byte[] get() {
        return this.value;
    }

    public int getByteLength() {
        return this.byteLength;
    }

    /**
     * 用当前对象和目标值进行异或运算
     *
     * @param target 目标值
     * @return 返回处理或的结果(新开辟一段内存空间)
     */
    public ByteStream xor(ByteStream target) throws Exception {
        if (this.byteLength != target.getByteLength()) {
            throw new Exception(CONS.DATA_MISMATCH.getMsg());
        }
        ByteStream res = new ByteStream(target.getByteLength());
        for (int i = 1; i <= 16; i++) {
            res.set(i, (byte) (this.get(i) ^ target.get(i)));
        }
        return res;
    }

    @Override
    public String toString() {
        return Arrays.toString(value);
    }

    public String toHexString() {
        StringBuilder res = new StringBuilder();
        for (byte b : value) {
            String s = Integer.toHexString(Byte.toUnsignedInt(b));
            if (s.length() != 2) {
                res.append('0').append(s);
            } else {
                res.append(s);
            }
        }
        return res.substring(0);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof ByteStream)) return false;
        return this.toString().equals(obj.toString());
    }
}
